<?php

namespace ASW\Utility\HttpClient;

/**
 * Class Response
 *
 * @package lib\Util\HttpClient
 *
 * @property-read string $url
 * @property-read string $httpVersion
 * @property-read int $httpCode
 * @property-read string $httpStatus
 * @property-read array $headers
 * @property-read array $redirects
 * @property-read array $cookies
 * @property-read string $body
 *
 * @property-read ResponseInfo $responseInfo
 */
class Response
{
    private array $_properties = [
        'url'         => '',
        'httpVersion' => '',
        'httpCode'    => 0,
        'httpStatus'  => '',
        'headers'     => [],
        'redirects'   => [],
        'cookies'     => [],
        'body'        => '',
    ];

    /**
     * @param string $responseStream
     * @param ResponseInfo $responseInfo
     *
     * @return Response
     *
     */
    public static function fromCurlResponse(string $responseStream, ResponseInfo $responseInfo): self
    {
        $instance                              = new self();
        $instance->_properties['responseInfo'] = $responseInfo;
        $instance->_properties['url']          = $responseInfo->url;
        $instance->_properties['body']         = substr($responseStream, $responseInfo->headerSize);

        $rawHeader         = substr($responseStream, 0, $responseInfo->headerSize);
        $rawHeader         = str_replace("\r\n", "\n", $rawHeader);
        $rawHeaderPackages = explode("\n\n", trim($rawHeader));

        $rawHeaderPackagesCount = count($rawHeaderPackages);
        echo "<!-- rawHeaderPackages count is $rawHeaderPackagesCount -->\n";

        for ($headerPackageIndex = 0; $headerPackageIndex < count($rawHeaderPackages); $headerPackageIndex++) {
            $headerPackage       = $rawHeaderPackages[$headerPackageIndex];
            $isLastHeaderPackage = $headerPackageIndex === count($rawHeaderPackages) - 1;
            if (!$isLastHeaderPackage) {
                $instance->_properties['redirects'][] = ResponseRedirect::fromResponseHeaderPackage($headerPackage);
                continue;
            }

            $headerPackageLines = explode("\n", trim($headerPackage));
            $headerFirstLine    = array_shift($headerPackageLines);
            if (1 === preg_match("/^(HTTP\/\d\.\d) (\d{3})(.*)$/", $headerFirstLine, $matches)) {
                $instance->_properties['httpVersion'] = $matches[1];
                $instance->_properties['httpCode']    = intval($matches[2]);
                $instance->_properties['httpStatus']  = $matches[3];
            }

            foreach ($headerPackageLines as $headerLine) {
                echo "<!-- headerLine: $headerLine -->\n";
                if (strpos($headerLine, ':') === false) continue;

                [$headerKey, $headerVal] = explode(":", $headerLine, 2);
                $headerKey = trim($headerKey);
                $headerKey = str_replace(' ', '-', ucwords(str_replace('-', ' ', $headerKey)));
                $headerVal = trim($headerVal);
                if ($headerKey == 'Set-Cookie') {
                    $instance->_properties['cookies'][] = ResponseCookie::fromSetCookieHeaderLine($headerVal);
                } else {
                    $instance->_properties['headers'][$headerKey] = $headerVal;
                }
            }
        }

        return $instance;
    }

    public function __get(string $propertyName)
    {
        if (!array_key_exists($propertyName, $this->_properties)) return null;

        return $this->_properties[$propertyName];
    }

    public function convertEncoding(string $from, string $to): self
    {
        $this->_properties['body'] = iconv($from, $to, $this->_properties['body']);

        return $this;
    }
}